package com.atguigu.tingshu.album.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserFeignClient;
import com.atguigu.tingshu.vo.album.*;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

	@Autowired
	private TrackInfoMapper trackInfoMapper;
	@Autowired
	private AlbumInfoMapper albumInfoMapper;
	@Autowired
	private VodService vodService;
	@Autowired
	private TrackStatMapper trackStatMapper;
	@Autowired
	private UserFeignClient userFeignClient;
	@Autowired
	private AlbumStatMapper albumStatMapper;

	/**
	 * 保存声音
	 *
	 * @param userId    用户ID
	 * @param trackInfo 专辑信息
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void saveTrackInfo(Long userId, TrackInfo trackInfo) {
		//1.根据专辑ID查询专辑信息-更新专辑信息；复用专辑封面图片
		AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfo.getAlbumId());

		//2.新增声音
		//2.1 设置声音额外基本信息：用户ID，声音排序序号，状态，来源
		trackInfo.setUserId(userId);
		trackInfo.setOrderNum(albumInfo.getIncludeTrackCount() + 1);
		trackInfo.setSource(SystemConstant.TRACK_SOURCE_USER);
		trackInfo.setStatus(SystemConstant.TRACK_STATUS_NO_PASS);
		if (StringUtils.isBlank(trackInfo.getCoverUrl())) {
			trackInfo.setCoverUrl(albumInfo.getCoverUrl());
		}
		//2.2 远程调用腾讯点播平台获取音频详情信息
		TrackMediaInfoVo mediaInfoVo = vodService.getMediaInfo(trackInfo.getMediaFileId());
		if (mediaInfoVo != null) {
			trackInfo.setMediaDuration(BigDecimal.valueOf(mediaInfoVo.getDuration()));
			trackInfo.setMediaSize(mediaInfoVo.getSize());
			trackInfo.setMediaType(mediaInfoVo.getType());
		}
		//2.3 新增声音
		trackInfoMapper.insert(trackInfo);
		Long trackId = trackInfo.getId();


		//3.更新专辑信息（包含声音数量）
		albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() + 1);
		albumInfoMapper.updateById(albumInfo);

		//4.初始化声音统计信息
		this.saveTrackStat(trackId, SystemConstant.TRACK_STAT_PLAY, 0);
		this.saveTrackStat(trackId, SystemConstant.TRACK_STAT_COLLECT, 0);
		this.saveTrackStat(trackId, SystemConstant.TRACK_STAT_PRAISE, 0);
		this.saveTrackStat(trackId, SystemConstant.TRACK_STAT_COMMENT, 0);

		//5.TODO 调用点播平台发起音频文件审核任务（异步审核）
		trackInfo.setStatus(SystemConstant.TRACK_STATUS_REVIEWING);
		String reviewTaskId = vodService.startReviewTask(trackInfo.getMediaFileId());
		trackInfo.setReviewTaskId(reviewTaskId);
		trackInfoMapper.updateById(trackInfo);
	}

	@Override
	public void saveTrackStat(Long trackId, String statType, int statNum) {
		TrackStat trackStat = new TrackStat();
		trackStat.setTrackId(trackId);
		trackStat.setStatType(statType);
		trackStat.setStatNum(statNum);
		trackStatMapper.insert(trackStat);
	}

	@Override
	public Page<TrackListVo> getUserTrackPage(Page<TrackListVo> pageInfo, TrackInfoQuery trackInfoQuery) {
		return trackInfoMapper.getUserTrackPage(pageInfo, trackInfoQuery);
	}

	@Override
	public void updateTrackInfo(TrackInfo trackInfo) {
		//1.判断音频文件是否变更
		// 1.1 根据声音ID查询声音记录得到“旧”的音频文件标识
		TrackInfo oldTrackInfo = trackInfoMapper.selectById(trackInfo.getId());
		//1.2 判断文件是否被更新
		if (!oldTrackInfo.getMediaFileId().equals(trackInfo.getMediaFileId())){
			//1.3 如果文件被更新，再次获取新音频文件信息更新：时长，大小，类型
			TrackMediaInfoVo mediaInfoVo = vodService.getMediaInfo(trackInfo.getMediaFileId());
			if (mediaInfoVo != null) {
				trackInfo.setMediaType(mediaInfoVo.getType());
				trackInfo.setMediaDuration(BigDecimal.valueOf(mediaInfoVo.getDuration()));
				trackInfo.setMediaSize(mediaInfoVo.getSize());
				trackInfo.setStatus(SystemConstant.TRACK_STATUS_NO_PASS);

			}
			//1.4 从点播平台删除旧的音频文件
			vodService.deleteMedia(oldTrackInfo.getMediaFileId());
			//TODO 变更后音频文件发起审核任务，重新关联审核任务ID
			//5.TODO 发起异步音视频审核任务 更新声音表 审核任务ID
			//5.1 方式一：如果是异步开启线程发起审核任务，将更新声音表逻辑放在审核方法里。不需要返回结果
			//5.2 方式二：如果是同步程发起审核任务，得到审核任务ID，同步更新声音表
			String reviewTaskId = vodService.startReviewTask(trackInfo.getMediaFileId());
			trackInfo.setStatus(SystemConstant.TRACK_STATUS_REVIEWING);
			trackInfo.setReviewTaskId(reviewTaskId);
			trackInfoMapper.updateById(trackInfo);
		}
		trackInfoMapper.updateById(trackInfo);
	}

	@Override
	public void removeTrackInfo(Long id) {
		//1.根据声音ID查询被删除声音记录 得到专辑ID及声音序号
		TrackInfo trackInfo = baseMapper.selectById(id);
		Long albumId = trackInfo.getAlbumId();
		Integer orderNum = trackInfo.getOrderNum();
		//2.更新该下专辑下声音序号确保连续
		LambdaUpdateWrapper<TrackInfo> updateWrapper = new LambdaUpdateWrapper<>();
		updateWrapper.eq(TrackInfo::getAlbumId, albumId);
		updateWrapper.gt(TrackInfo::getOrderNum, orderNum);
		updateWrapper.setSql("order_num = order_num - 1");
		baseMapper.update(null, updateWrapper);

		//3.删除声音记录
		baseMapper.deleteById(id);

		//4.删除声音统计
		trackStatMapper.delete(new LambdaQueryWrapper<TrackStat>().eq(TrackStat::getTrackId, id));

		//5.更新专辑包含声音数量-1
		AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
		albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() - 1);
		albumInfoMapper.updateById(albumInfo);

		//6.删除点播平台音频文件
		vodService.deleteMedia(trackInfo.getMediaFileId());
	}

	/**
	 * 分页查询当前用户可见声音列表-动态判断声音付费标识
	 *
	 * @param pageInfo 分页对象
	 * @param albumId  专辑ID
	 * @param userId   用户ID
	 * @return
	 */
    @Override
    public Page<AlbumTrackListVo> getAlbumTrackPage(Page<AlbumTrackListVo> pageInfo, Long albumId, Long userId) {
		pageInfo = baseMapper.getAlbumTrackPage(pageInfo, albumId);
		//根据专辑ID查询专辑信息
		AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
		//付费类型: 0101-免费、0102-vip免费、0103-付费
		String payType = albumInfo.getPayType();
		//免费试听级数
		Integer tracksForFree = albumInfo.getTracksForFree();
		//处理未登陆的情况
		if (userId == null){
			if(SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equals(payType) || SystemConstant.ALBUM_PAY_TYPE_REQUIRE.equals(payType)){
				//除去试听其他声音将付费标识全部设置true
				pageInfo.getRecords()
						.stream()
						.filter(vo -> vo.getOrderNum() > tracksForFree)
						.forEach(vo -> vo.setIsShowPaidMark(true));
			}
		}else {
			// 处理已登陆情况
			// 判断用户身份
			UserInfoVo userInfoVo = userFeignClient.getUserInfoVo(userId).getData();
			Assert.notNull(userInfoVo, "用户：{}不存在！", userId);
			Boolean isVIP = false;
			if (userInfoVo.getIsVip().intValue() == 1 && userInfoVo.getVipExpireTime().after(new Date())){
				//vip标识等于1且会员在有效期内
				isVIP = true;
			}
			//是否需要进一步判断声音购买情况
			Boolean needCheckBuyState = false;

			//如果普通用户查看付费类型为“VIP免费”专辑，进一步查看本页中声音购买情况
			if (!isVIP && SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equals(payType)){
				needCheckBuyState = true;
			}
			//判断专辑付费类型=付费 所有用户都需要进一步判断声音购买情况
			if (SystemConstant.ALBUM_PAY_TYPE_REQUIRE.equals(payType)) {
				needCheckBuyState = true;
			}
			//如果需要进一步判断声音购买情况， 远程调用用户服务查询用户购买声音情况
			if (needCheckBuyState){
				List<Long> needCheckBuyStateTrackIds = pageInfo.getRecords()
						.stream()
						.filter(track -> track.getOrderNum() > tracksForFree)
						.map(AlbumTrackListVo::getTrackId)
						.collect(Collectors.toList());
				Map<Long, Integer> buyStateMap = userFeignClient.userIsPaidTrack(userId, albumId, needCheckBuyStateTrackIds).getData();
				//根据购买情况设置付费标识（去除试听标识），未购买声音设置为 true
				if (CollUtil.isNotEmpty(buyStateMap)){
					pageInfo.getRecords()
							.stream()
							.filter(track -> track.getOrderNum() > tracksForFree)
							.forEach(albumTrackVo->albumTrackVo.setIsShowPaidMark(buyStateMap.get(albumTrackVo.getTrackId()) == 0));
				}
			}
		}
        return pageInfo;
    }

	/**
	 * 更新声音统计数值
	 * 注意：如果声音被播放，被评论 所属专辑也需要更新统计数值
	 *
	 * @param mqVo
	 */
    @Override
	@Transactional(rollbackFor = Exception.class)
    public void updateTrackStat(TrackStatMqVo mqVo) {
        //更新声音统计计数值
		//1.更新声音统计数值
		LambdaUpdateWrapper<TrackStat> updateWrapper = new LambdaUpdateWrapper<>();
		updateWrapper.eq(TrackStat::getTrackId, mqVo.getTrackId());
		updateWrapper.eq(TrackStat::getStatType, mqVo.getStatType());
		updateWrapper.setSql("stat_num=stat_num+" + mqVo.getCount());
		trackStatMapper.update(null, updateWrapper);
		//如果统计类型是：声音播放 所属专辑统计信息也一并修改
		if (SystemConstant.TRACK_STAT_PLAY.equals(mqVo.getStatType())) {
			LambdaUpdateWrapper<AlbumStat> albumStatLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
			albumStatLambdaUpdateWrapper.eq(AlbumStat::getAlbumId, mqVo.getAlbumId());
			albumStatLambdaUpdateWrapper.eq(AlbumStat::getStatType, SystemConstant.ALBUM_STAT_PLAY);
			albumStatLambdaUpdateWrapper.setSql("stat_num = stat_num+" + mqVo.getCount());
			albumStatMapper.update(null, albumStatLambdaUpdateWrapper);
		}
		//如果统计类型是：声音评论 所属专辑统计信息也一并修改
		if (SystemConstant.TRACK_STAT_COMMENT.equals(mqVo.getStatType())) {
			LambdaUpdateWrapper<AlbumStat> albumStatLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
			albumStatLambdaUpdateWrapper.eq(AlbumStat::getAlbumId, mqVo.getAlbumId());
			albumStatLambdaUpdateWrapper.eq(AlbumStat::getStatType, SystemConstant.ALBUM_STAT_COMMENT);
			albumStatLambdaUpdateWrapper.setSql("stat_num = stat_num+" + mqVo.getCount());
			albumStatMapper.update(null, albumStatLambdaUpdateWrapper);
		}
    }

	@Override
	public TrackStatVo getTrackStatVo(Long trackId) {

		return trackInfoMapper.getTrackStatVo(trackId);
	}

    @Override
    public List<Map<String, Object>> getUserTrackPaidList(Long userId, Long trackId) {
		//根据选择起始声音ID得到声音序号、专辑ID
		TrackInfo trackInfo = baseMapper.selectById(trackId);
		Integer orderNum = trackInfo.getOrderNum();
		Long albumId = trackInfo.getAlbumId();

		//根据声音序号 专辑ID 按照序号升序得到待购买声音列表（可能包含已购买的声音）
		List<TrackInfo> trackInfoList = baseMapper.selectList(new LambdaQueryWrapper<TrackInfo>()
				.eq(TrackInfo::getAlbumId, albumId)
				.ge(TrackInfo::getOrderNum, orderNum)
				.orderByDesc(TrackInfo::getOrderNum));

		//远程调用用户服务查询用户购买声音情况
		List<Long> userPaidTrackIdList = userFeignClient.getUserPaidTrackIdList(albumId).getData();
		if (CollUtil.isNotEmpty(userPaidTrackIdList)){
			trackInfoList = trackInfoList.stream()
					.filter(track -> !userPaidTrackIdList.contains(track.getId())).collect(Collectors.toList());
		}

		//处理待购买声音列表，过滤掉已购买声音
		int size = trackInfoList.size();
		AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
		BigDecimal price = albumInfo.getPrice();
		//构建"本集"分集购买对象
		List<Map<String, Object>> list = new ArrayList<>();
		Map<String, Object> currMap = new HashMap<>();
		currMap.put("name", "本集");
		currMap.put("price", price);
		currMap.put("trackCount", 1);
		list.add(currMap);

		//根据未购买声音数量循环最多构建6个分集购买对象（50集）
		//例如：size=12 展示 后10集，全集     size=35 展示 后10集 后20集 后30集 全集
		for (int i = 10; i <= 50; i += 10) {
			if (size > i) {
				Map<String, Object> map = new HashMap<>();
				map.put("name", "后" + i + "集");
				map.put("price", price.multiply(BigDecimal.valueOf(i)));
				map.put("trackCount", i);
				list.add(map);
			} else {
				Map<String, Object> map = new HashMap<>();
				map.put("name", "全集(" + size + "集）");
				map.put("price", price.multiply(BigDecimal.valueOf(size)));
				map.put("trackCount", size);
				list.add(map);
				break;
			}
		}
        return list;
    }

	/**
	 * 查询当前用户未购买声音列表
	 *
	 * @param userId     用户ID
	 * @param trackId    点击付费标识声音ID，将该声音作为起始标准
	 * @param trackCount 购买数量
	 * @return 待购声音列表
	 */
	@Override
	public List<TrackInfo> getWaitBuyTrackList(Long userId, Long trackId, Integer trackCount) {
		//1.根据声音ID查询到“起始”待购声音记录，得到当前声音序号、所属专辑ID
		TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
		Integer orderNum = trackInfo.getOrderNum();
		Long albumId = trackInfo.getAlbumId();

		//2.远程调用用户服务获取已购买声音ID列表
		List<Long> userPaidTrackIdList = userFeignClient.getUserPaidTrackIdList(albumId).getData();

		//3.获取待购声音列表 查询条件：专辑ID，序号，已购声音ID 。排序字段：序号  。返回数量：购买数量
		LambdaQueryWrapper<TrackInfo> queryWrapper = new LambdaQueryWrapper<>();
		//3.1 等值查询专辑标题
		queryWrapper.eq(TrackInfo::getAlbumId, albumId);
		//3.2 大于等于当前选购声音序号
		queryWrapper.ge(TrackInfo::getOrderNum, orderNum);
		if (CollectionUtil.isNotEmpty(userPaidTrackIdList)) {
			//3.3 如果存在已购买声音，去除已购买声音ID
			queryWrapper.notIn(TrackInfo::getId, userPaidTrackIdList);
		}
		//3.4 按照声音序号升序
		queryWrapper.orderByAsc(TrackInfo::getOrderNum);
		//3.5 按用户选择购买数量获取声音列表
		queryWrapper.last("LIMIT " + trackCount);
		//3.6 执行查询列：多查询了专辑ID，需要在订单服务进行算价格需要获取专辑中价格
		queryWrapper.select(TrackInfo::getId, TrackInfo::getTrackTitle, TrackInfo::getCoverUrl, TrackInfo::getAlbumId);
		List<TrackInfo> list = trackInfoMapper.selectList(queryWrapper);
		return list;
	}
}
